package net.zoneland.zrdp.common.utils;


import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;


import com.google.common.base.CaseFormat;

import net.zoneland.zrdp.common.constant.Constants;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.AntPathMatcher;
import org.apache.commons.collections4.CollectionUtils;

/**
 * 字符串工具类
 *
 * @author zonevue
 */
public class StringUtilPlus extends org.apache.commons.lang3.StringUtils
{

    /** 下划线 */
    private static final char SEPARATOR = '_';

    private static final int MAX_LENGTH = 4000;

    private static final int NO_CHECK_LENGTH = 1000;

    /**
     * 把字符串截取到MAX_LENGTH 字符长度的新字符串
     * @param inputText 输入字符串
     * @return 返回的字符
     */
    public static String truncateToValidLengthForMysql(final String inputText) {

        if (inputText.length() <= MAX_LENGTH) {
            return inputText;
        }
        return inputText.substring(0, MAX_LENGTH);
    }

    /**
     * 把字符串截取到字符集为utf-8时小于MAX_UTF8_LENGTH 字节长度的新字符串
     * （主要是oracle数据库表字段varchar2(4000) 这个长度为字节数；mysql varchar(4000)长度是字符数，字节长度还和mysql的字符集相关）
     * @param inputText 输入字符串
     * @return 返回的字符(注意：返回字符串的最后几个字符可能是中文或表情符截断从而出现的乱码)
     */
    public static String truncateToValidUtf8LengthForOracle(final String inputText) {
        // 大部分字符长度小于等于1000，不需要做截取，直接判断提高效率
        if (inputText.length() <= NO_CHECK_LENGTH) {
            return inputText;
        }
        final byte[] utf8Bytes = inputText.getBytes(StandardCharsets.UTF_8);

        if (utf8Bytes.length <= MAX_LENGTH) {
            return inputText;
        }
        // 注：可能会造成中文或表情字符截断的现象。
        return new String(utf8Bytes, 0, MAX_LENGTH, StandardCharsets.UTF_8);
    }

    /**
     * 是否为http(s)://开头
     *
     * @param link 链接
     * @return 结果
     */
    public static boolean isHttp(final String link) {
        return startsWithAny(link, Constants.HTTP, Constants.HTTPS);
    }


    /**
     * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
     *
     * @param cs 指定字符串
     * @param searchCharSequences 需要检查的字符串数组
     * @return 是否包含任意一个字符串
     */
    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {

        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
            return false;
        }

        return Arrays.stream(searchCharSequences).anyMatch(testStr -> containsIgnoreCase(cs, testStr));
    }


    /**
     * 驼峰转下划线命名
     */
    public static String toUnderScoreCase(final String str) {

        if (str == null) {
            return null;
        }
        return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, str);

    }

    /**
     * 是否包含字符串
     *
     * @param str 验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inStringIgnoreCase(final String str, final String... strs) {
        if (isEmpty(str) || ArrayUtils.isEmpty(strs)) {
            return false;
        }

        return Arrays.stream(strs).anyMatch(testStr -> equalsIgnoreCase(str, testStr));
    }

    /**
     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。 例如：HELLO_WORLD->HelloWorld
     *
     * @param name 转换前的下划线大写方式命名的字符串
     * @return 转换后的驼峰式命名的字符串
     */
    public static String convertToCamelCase(final String name) {
        // 快速检查
        if (name == null || name.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!name.contains("_")) {
            // 不含下划线，仅将首字母大写
            return name.substring(0, 1).toUpperCase() + name.substring(1);
        }
        final String camelStr = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name);
        return camelStr.substring(0, 1).toUpperCase() + camelStr.substring(1);
    }

    /**
     * 驼峰式命名法
     * 例如：user_name->userName
     */
    public static String toCamelCase(final String str) {
        if (str == null) {
            return null;
        }
        if (str.indexOf(SEPARATOR) == -1) {
            return str;
        }
        final String lowerStr = str.toLowerCase();
        return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, lowerStr);
    }

    /**
     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
     *
     * @param str 指定字符串
     * @param strs 需要检查的字符串数组
     * @return 是否匹配
     */
    public static boolean matches(final String str, final List<String> strs) {
        if (isEmpty(str) || CollectionUtils.isEmpty(strs)) {
            return false;
        }

        return strs.stream().anyMatch(pattern -> isMatch(pattern, str));
    }


    /**
     * 判断url是否与规则配置:
     * ? 表示单个字符;
     * * 表示一层路径内的任意字符串，不可跨层级;
     * ** 表示任意层路径;
     *
     * @param pattern 匹配规则
     * @param url 需要匹配的url
     * @return  是否匹配
     */
    public static boolean isMatch(final String pattern, final String url) {
        final AntPathMatcher matcher = new AntPathMatcher();
        return matcher.match(pattern, url);
    }


    /**
     * 数字左边补齐0，使之达到指定长度。注意，如果数字转换为字符串后，长度大于size，则只保留 最后size个字符。
     *
     * @param num 数字对象
     * @param size 字符串指定长度
     * @return 返回数字的字符串格式，该字符串为指定长度。
     */
    public static String padL(final Number num, final int size) {
        final String string = num.toString();
        final int length = string.length();
        if (length > size) {
            return string.substring(length - size, length);
        }
        return leftPad(num.toString(), size, '0');
    }

}
